package com.example.concurrent.chapter14;

import java.net.Socket;
import java.sql.Connection;

/**
 * @author Liuqz
 * @date 2018/11/25 20:29
 *
 * Double-Check单例模式
 *
 * 该单例模式,提供了一种高效的数据同步策略,那就是首次初始化时加锁,之后则允许多个线程同时进行getInstance方法的调用来获得类的实例
 *
 * 既满足了懒加载,又保证了instance实例的唯一性,允许多个线程同时进行getInstance方法的调用来获得类的实例
 * 但是这种方式在多线程的情况下有可能会引起空指针异常.
 *
 * 在DoubleCheckSingleton的构造函数中,需要分别实例化conn和socket两个资源,还有DoubleCheckSingleton自身,根据JVM运行时指令重排序和Happens-Before规则,
 * 这三者之间的实例化顺序并无前后关系的约束,那么极有可能是instance最先被实例化,而conn和socket并未完成实例化,未完成初始化的实例调用其方法将会抛出空指针异常
 *
 */

//final不允许被继承
public final class DoubleCheckSingleton {

    private byte[] data = new byte[1024];

    private static DoubleCheckSingleton instance = null;

    Connection conn;

    Socket socket;

    public DoubleCheckSingleton() {
        this.conn = conn;
        this.socket = socket;
    }

    public static DoubleCheckSingleton getInstance() {
        //当instance为null时,进入同步代码块,同时该判断避免了每次都需要进入同步代码块,可以提高效率
        if (null == instance) {
            //只有一个线程能够获得DoubleCheckSingleton.class关联的monitor
            synchronized (DoubleCheckSingleton.class) {
                //判断如果instance为null则创建
                if (null == instance) {
                    return new DoubleCheckSingleton();
                }
            }
        }
        return instance;
    }

}
